//
//  priterModule.m
//  fetailAdmin
//
//  Created by eval on 2018/8/25.
//  Copyright © 2018年 Facebook. All rights reserved.
//

#import "PrinterModule.h"
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>

@implementation PrinterModule

NSString* EVENT_NAME = @"printerEvent";

RCT_EXPORT_MODULE(FetailPrinter);

- (NSArray<NSString *> *)supportedEvents{
  return @[EVENT_NAME];
}

RCT_EXPORT_METHOD(test){
  NSLog(@"test");
  [self sendEventWithName:EVENT_NAME body:@{@"type":@"test"}];
}

RCT_EXPORT_METHOD(search:(NSString*)type:(RCTResponseSenderBlock)callback){
  NSArray *portInfoArray = [SMPort searchPrinter:type];
  NSMutableArray *call = [[NSMutableArray alloc]init];
  for(int i = 0;i < [portInfoArray count];i++){
    PortInfo *info = [portInfoArray objectAtIndex:i];
    NSDictionary *item = @{@"modelName":info.modelName,@"portName":info.portName,@"macAddress":info.macAddress};
    [call addObject:item];
  }
  
   callback(@[[NSNull null],call]);
}

- (void)sendCommands:(NSData *)commands:(SMPort*)port {
  dispatch_async(GlobalQueueManager.sharedManager.serialQueue, ^{
      [self sendCommands:commands port:port completionHandler:^(BOOL result, NSString *title, NSString *message) {
        [self sendEventWithName:EVENT_NAME body:@{@"type":@"send",@"msg":message}];
      }];
  });
}
//
RCT_EXPORT_METHOD(send:(NSDictionary*)data:(RCTResponseSenderBlock)callback){
  NSData *commands =[self createQrCodeData:StarIoExtEmulationStarGraphic :data[@"path"]];
  NSString *portName = @"TCP:192.168.0.110";//data[@"portName"];
  [self sendCommands:commands portName:portName portSettings:@"TSP100" timeout:10000 completionHandler:callback];
}
//用于链接，是否可用。
RCT_EXPORT_METHOD(connect:(NSDictionary*)data:(RCTResponseSenderBlock)callback){
  @try{
    SMPort *port = [SMPort getPort:data[@"portName"]:@"TSP100" :10000];
    if([port getOnlineStatus]){
      callback(@[[NSNull null]]);
    }else{
      callback(@[@400,@"conncet error!"]);
    }
  }
  @catch(NSException *e){
    callback(@[@500,@"conncet timeout!"]);
  }
}
//打开钱箱
RCT_EXPORT_METHOD(openCash:(NSDictionary*)data:(RCTResponseSenderBlock)callback){
  SCBPeripheralChannel channel = SCBPeripheralChannelNo1;
  if([data[@"channel"] integerValue] == 2){
    channel = SCBPeripheralChannelNo2;
  }
  NSData *commands = [self createData:StarIoExtEmulationStarGraphic channel:channel];
  [self sendCommands:commands portName:data[@"portName"] portSettings:@"TSP100" timeout:10000 completionHandler:callback];
}
- (NSData *)createQrCodeData:(StarIoExtEmulation)emulation:(NSString*)path{
//   NSData *otherData = [@"爱你哦" dataUsingEncoding:NSUTF8StringEncoding];
   
   ISCBBuilder *builder = [StarIoExt createCommandBuilder:emulation];
   
   [builder beginDocument];
   
   
   UIImage *img = [UIImage imageWithContentsOfFile:path];
   
   [builder appendBitmap:img diffusion:NO];
   [builder appendCutPaper:SCBCutPaperActionFullCutWithFeed];
   [builder endDocument];
   
   return [builder.commands copy];
 }
-(BOOL)sendCommands:(NSData *)commands
port:(SMPort *)port
completionHandler:(SendCompletionHandler)completionHandler {
  BOOL result = NO;
  
  NSString *title   = @"";
  NSString *message = @"";
  
  @try {
    while (YES) {
      if (port == nil) {
        title = @"Fail to Open Port";
        break;
      }
      
      StarPrinterStatus_2 printerStatus;
      
      [port beginCheckedBlock:&printerStatus :2];
      
      if (printerStatus.offline == SM_TRUE) {
        title   = @"Printer Error";
        message = @"Printer is offline (BeginCheckedBlock)";   
        break;
      }
      
      NSDate *startDate = [NSDate date];
      
      uint32_t total = 0;
      
      while (total < (uint32_t) commands.length) {
        uint32_t written = [port writePort:commands.bytes :total :(uint32_t) commands.length - total];
        
        total += written;
        
        if ([[NSDate date] timeIntervalSinceDate:startDate] >= 30.0) {     // 30000mS!!!
          title   = @"Printer Error";
          message = @"Write port timed out";
          break;
        }
      }
      
      if (total < (uint32_t) commands.length) {
        break;
      }
      
      port.endCheckedBlockTimeoutMillis = 30000;     // 30000mS!!!
      
      [port endCheckedBlock:&printerStatus :2];
      
      if (printerStatus.offline == SM_TRUE) {
        title   = @"Printer Error";
        message = @"Printer is offline (EndCheckedBlock)";
        break;
      }
      
      title   = @"Send Commands";
      message = @"Success";
      
      result = YES;
      break;
    }
  }
  @catch (PortException *exc) {
    title   = @"Printer Error";
    message = @"Write port timed out (PortException)";
  }
  
  if (completionHandler != nil) {
    completionHandler(result, title, message);
  }
  
  return result;
}
-(BOOL)sendCommands:(NSData *)commands
portName:(NSString *)portName
portSettings:(NSString *)portSettings
timeout:(NSInteger)timeout
completionHandler:(RCTResponseSenderBlock)callBack {
  BOOL result = NO;
  
  NSString *title   = @"";
  NSString *message = @"";
  
  if (timeout > UINT32_MAX) {
    timeout = UINT32_MAX;
  }
  
  SMPort *port = nil;
  
  @try {
    while (YES) {
      port = [SMPort getPort:portName :portSettings :(uint32_t) timeout];
      
      if (port == nil) {
        title = @"Fail to Open Port";
        break;
      }
      
      // Sleep to avoid a problem which sometimes cannot communicate with Bluetooth.
      // (Refer Readme for details)
      NSOperatingSystemVersion version = {11, 0, 0};
      BOOL isOSVer11OrLater = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:version];
      if ((isOSVer11OrLater) && ([portName.uppercaseString hasPrefix:@"BT:"])) {
        [NSThread sleepForTimeInterval:0.2];
      }
      
      StarPrinterStatus_2 printerStatus;
      
      [port beginCheckedBlock:&printerStatus :2];
      
      if (printerStatus.offline == SM_TRUE) {
        title   = @"Printer Error";
        message = @"Printer is offline (BeginCheckedBlock)";
        break;
      }
      
      NSDate *startDate = [NSDate date];
      
      uint32_t total = 0;
      
      while (total < (uint32_t) commands.length) {
        uint32_t written = [port writePort:(unsigned char *) commands.bytes :total :(uint32_t) commands.length - total];
        
        total += written;
        
        if ([[NSDate date] timeIntervalSinceDate:startDate] >= 30.0) {     // 30000mS!!!
          title   = @"Printer Error";
          message = @"Write port timed out";
          callBack(@[@"error"]);
          break;
        }
      }
      
      if (total < (uint32_t) commands.length) {
        callBack(@[@"error"]);
        break;
      }
      
      port.endCheckedBlockTimeoutMillis = 30000;     // 30000mS!!!
      
      [port endCheckedBlock:&printerStatus :2];
      
      if (printerStatus.offline == SM_TRUE) {
        title   = @"Printer Error";
        message = @"Printer is offline (EndCheckedBlock)";
        break;
      }
      
      title   = @"Send Commands";
      message = @"Success";
      result = YES;
      break;
    }
  }
  @catch (PortException *exc) {
    title   = @"Printer Error";
    message = @"Write port timed out (PortException)";
  }
  @finally {
    if (port != nil) {
      [SMPort releasePort:port];
      
      port = nil;
    }
  }
  callBack(@[[NSNull null], title, message]);
}

- (NSData *)createData:(StarIoExtEmulation)emulation
               channel:(SCBPeripheralChannel)channel {
  ISCBBuilder *builder = [StarIoExt createCommandBuilder:emulation];
  
  [builder beginDocument];
  
  [builder appendPeripheral:channel];
  
  [builder endDocument];
  
  return [builder.commands copy];
}
@end;
